﻿//-----------------------------------------------------------------------
// <copyright file="ApplicationFactory.cs" company="OOHM PROCESSAMENTO DE DADOS LTDA.">
//     Microsoft Public License (MS-PL) This license governs use of the accompanying
//     software. If you use the software, you accept this license. If you do not
//     accept the license, do not use the software. 1. Definitions The terms "reproduce,"
//     "reproduction," "derivative works," and "distribution" have the same meaning
//     here as under U.S. copyright law. A "contribution" is the original software,
//     or any additions or changes to the software. A "contributor" is any person
//     that distributes its contribution under this license. "Licensed patents"
//     are a contributor's patent claims that read directly on its contribution.
//     2. Grant of Rights (A) Copyright Grant- Subject to the terms of this license,
//     including the license conditions and limitations in section 3, each contributor
//     grants you a non-exclusive, worldwide, royalty-free copyright license to
//     reproduce its contribution, prepare derivative works of its contribution,
//     and distribute its contribution or any derivative works that you create.
//     (B) Patent Grant- Subject to the terms of this license, including the license
//     conditions and limitations in section 3, each contributor grants you a non-exclusive,
//     worldwide, royalty-free license under its licensed patents to make, have
//     made, use, sell, offer for sale, import, and/or otherwise dispose of its
//     contribution in the software or derivative works of the contribution in
//     the software. 3. Conditions and Limitations (A) No Trademark License- This
//     license does not grant you rights to use any contributors' name, logo, or
//     trademarks. (B) If you bring a patent claim against any contributor over
//     patents that you claim are infringed by the software, your patent license
//     from such contributor to the software ends automatically. (C) If you distribute
//     any portion of the software, you must retain all copyright, patent, trademark,
//     and attribution notices that are present in the software. (D) If you distribute
//     any portion of the software in source code form, you may do so only under
//     this license by including a complete copy of this license with your distribution.
//     If you distribute any portion of the software in compiled or object code
//     form, you may only do so under a license that complies with this license.
//     (E) The software is licensed "as-is." You bear the risk of using it. The
//     contributors give no express warranties, guarantees or conditions. You may
//     have additional consumer rights under your local laws which this license
//     cannot change. To the extent permitted under your local laws, the contributors
//     exclude the implied warranties of merchantability, fitness for a particular
// </copyright>
//-----------------------------------------------------------------------
#define MOCK// #define SQLnamespace AbstractSaaSTemplate.Kernel.Factories
{
    using System;
    using System.Web.Mvc;
    using System.Web.Routing;
    using AbstractSaaSTemplate.Application.Mvc;
    using AbstractSaaSTemplate.Domain;
    using AbstractSaaSTemplate.Kernel;
    using AbstractSaaSTemplate.Kernel.Compilations;
    using AbstractSaaSTemplate.Kernel.Exceptions;
    using Ninject;

    /// <summary>
    /// Co-Constructs the controllers which are created when invoking any MVC controller action.
    /// Also provides functionality of creation of any service or task available in the system.
    /// </summary>
    public sealed class ApplicationFactory : DefaultControllerFactory
    {
        /// <summary>
        /// Initializes a new instance of the ApplicationFactory class.
        /// </summary>
        public ApplicationFactory()
        {
#if MOCK
            var compilation = new DevelopmentKernel();
#endif

#if SQL
            var compilation = new Win2K8WithSQLServerKernel();
#endif

            this.Kernel = compilation;
        }
        
        /// <summary>
        /// Gets the current kernel activated for the application.
        /// </summary>
        public IKernelCompilation Kernel { get; private set; }

        /// <summary>
        /// Creates the instance of the controller using the active kernel.
        /// </summary>
        /// <param name="requestContext">The context of the request</param>
        /// <param name="controllerName">The name of the controller.</param>
        /// <returns>Retrieves an instance of the controller if successfully resolved</returns>
        public override IController CreateController(
            RequestContext requestContext,
            string controllerName)
        {
            if (this.Kernel == null)
            {
                return null;
            }

            var controllerDefinition = this.GetControllerType(
                requestContext,
                controllerName);

            // the control may not be found.
            // we have to be careful with this situation
            if (controllerDefinition == null)
            {
                return null;
            }

            var controller = this.Kernel.Instance.Get(controllerDefinition) as IController;
            return TreatAndRetrieveController(controller);
        }
        
        /// <summary>
        /// Retrieves an instance of the controller using this class factory.
        /// </summary>
        /// <typeparam name="TController">The type of the controller which should be created</typeparam>
        /// <returns>Returns an instance of the controller with all dependencies available in the compilation injected.</returns>
        public TController CreateControllerFor<TController>() where TController : ApplicationController
        {
            var controller = this.Kernel.Instance.Get<TController>();
            return (TController) TreatAndRetrieveController(controller);
        }

        /// <summary>
        /// Creates the instance of the any IService implemented from the implementation injected in the system.
        /// </summary>
        /// <typeparam name="TService">The type of the service for which we will receive an implementation</typeparam>
        /// <returns>Retrieves an instance of the principal if successfully resolved</returns>
        public TService CreateServiceFor<TService>() where TService : IService
        {
            var type = typeof(TService);

            if (this.Kernel.Instance == null)
            {
                throw new NoKernelInstanceAvailableException();
            }

            var customPrincipal = (TService)this.Kernel.Instance.GetService(type);
            return customPrincipal;
        }

        /// <summary>
        /// Creates the instance of the any IRepository implemented from the implementation injected in the system.
        /// </summary>
        /// <typeparam name="TRepository">The type of the service for which we will receive an implementation</typeparam>
        /// <returns>Retrieves an instance of the principal if successfully resolved</returns>
        public TRepository CreateRepositoryFor<TRepository>() where TRepository : IRepository
        {
            var type = typeof(TRepository);

            if (this.Kernel.Instance == null)
            {
                throw new NoKernelInstanceAvailableException();
            }

            var customPrincipal = (TRepository)this.Kernel.Instance.GetService(type);
            return customPrincipal;
        }

        /// <summary>
        /// Creates the instance of the task using the current kernel.
        /// </summary>
        /// <typeparam name="TTask">The implementation of the task which we want to retrieve.</typeparam>
        /// <returns>Retrieves an instance of the task if successfully resolved</returns>
        public TTask CreateTaskFor<TTask>() where TTask : TaskBase
        {
            if (this.Kernel.Instance == null)
            {
                return default(TTask);
            }

            var type = typeof(TTask);
            var service = (TTask)this.Kernel.Instance.GetService(type);
            return service;
        }

        /// <summary>
        /// Retrieves a controller treated with all care it demans for this application,
        /// including default information loaded for all controllers, for example.
        /// </summary>
        /// <param name="controller">The controller which will be treated</param>
        /// <returns>Returns a controller treated as necessary for this application.</returns>
        private static IController TreatAndRetrieveController(IController controller)
        {
            if (controller == null)
            {
                throw new ArgumentNullException("controller");
            }

            return controller;
        }
    }
}


